<?php
require_once(realpath(dirname(__FILE__)."/config.php"));
/**
 * @author Andreas Wiik
 * @abstract 
 * Script for automating Google Search Appliance Admin Console tasks.
 * 	Supports generating reports. Inspired by http://gsa-admin-toolkit.googlecode.com/svn/trunk/adminconsole.py
 *  
 * 
 * @license  
 * 
 # Copyright (C) 2009 Norwegian Broadcasting Corporation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
 #      http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 *
 * @version 0.1
 * 
 * @uses curl
 * 
 * @example 
 * 
 */
class GSA_Admin{
	public $baseUrl					= 'http://madmzgsa.dmz.nrk.no:8000/EnterpriseController';
	public $waitSeconds				= 5;
	public $waitIterations			= 1000;
	public $topCount				= 100;
	public $reportName				= "monthlyReport";
	public $collection 				= "default_collection";
	protected $username				= "";
	protected $password				= "";
	protected $cookiefolder			= COOKIEFOLDER;// "cookies/";
	public $cookiefile				= "cookiefile";
	public $reportXmlString			= "";
	protected $reportFolder			= XMLFOLDER;// 'xml/';
	protected $reportFile			= '';
	//protected $basefolder			= BASEFOLDER;
	public		$withResults		= "true";
	public 		$dateFormat			= "range";//month,date,recent,range	
	public 		$recentDate			= "";
	public 		$dateMonth			= 0;
	public 		$dateDay			= 0;
	public 		$dateYear 			= 0;
	public 		$monthMonth			= 0;
	public 		$monthYear			= 0;
	public 		$rangeFromMonth		= 0;
	public 		$rangeFromDay		= 0;
	public 		$rangeFromYear		= 0;
	public 		$rangeToMonth		= 0;
	public 		$rangeToDay			= 0;
	public 		$rangeToYear		= 0;
	public		$rangeDays			= 30;
	public		$verbose			= true;
	public		$simpleXml			= null;
	protected	$security_token		= "";
	
	/**
	 * Constructor, sets attributes based on $paramarray
	 *
	 * @param array $paramarray
	 */
	public function __construct($paramarray = array()){
		if(isset($paramarray["rangeDays"])&&(!empty($paramarray["rangeDays"]))){
            $this->rangeDays = $paramarray["rangeDays"];
        }
		if(isset($paramarray["verbose"])&&(!empty($paramarray["verbose"]))&&is_bool($paramarray["verbose"])){
            $this->verbose = $paramarray["verbose"];
        }
		if(isset($paramarray["baseUrl"])&&(!empty($paramarray["baseUrl"]))){
            $this->baseUrl = $paramarray["baseUrl"];
        }
		if(isset($paramarray["waitSeconds"])&&(!empty($paramarray["waitSeconds"]))){
            $this->waitSeconds = $paramarray["waitSeconds"];
        }
		if(isset($paramarray["waitIterations"])&&(!empty($paramarray["waitIterations"]))){
            $this->waitIterations = $paramarray["waitIterations"];
        }
		if(isset($paramarray["topCount"])&&(!empty($paramarray["topCount"]))){
            $this->topCount = $paramarray["topCount"];
        }
		if(isset($paramarray["collection"])&&(!empty($paramarray["collection"]))){
            $this->collection = $paramarray["collection"];
        }
		if(isset($paramarray["reportName"])&&(!empty($paramarray["reportName"]))){
            $this->reportName = $paramarray["reportName"];
        }
		if(isset($paramarray["username"])&&(!empty($paramarray["username"]))){
            $this->username = $paramarray["username"];
        }
		if(isset($paramarray["password"])&&(!empty($paramarray["password"]))){
            $this->password = $paramarray["password"];
        }
		if(isset($paramarray["cookiefile"])&&(!empty($paramarray["cookiefile"]))){
            $this->cookiefile = $paramarray["cookiefile"];
        }
		if(isset($paramarray["reportXmlString"])&&(!empty($paramarray["reportXmlString"]))){
            $this->reportXmlString = $paramarray["reportXmlString"];
        }
		if(isset($paramarray["reportFile"])&&(!empty($paramarray["reportFile"]))){
            $this->reportFile = $paramarray["reportFile"];
        }
		if(isset($paramarray["withResults"])&&(!empty($paramarray["withResults"]))){
            $this->withResults = $paramarray["withResults"];
        }
		if(isset($paramarray["dateFormat"])&&(!empty($paramarray["dateFormat"]))){
            $this->dateFormat = $paramarray["dateFormat"];
        }
		if(isset($paramarray["recentDate"])&&(!empty($paramarray["recentDate"]))){
            $this->recentDate = $paramarray["recentDate"];
        }
		if(isset($paramarray["dateMonth"])&&(!empty($paramarray["dateMonth"]))){
            $this->dateMonth = $paramarray["dateMonth"];
        }
		if(isset($paramarray["dateDay"])&&(!empty($paramarray["dateDay"]))){
            $this->dateDay = $paramarray["dateDay"];
        }
		if(isset($paramarray["dateYear"])&&(!empty($paramarray["dateYear"]))){
            $this->dateYear = $paramarray["dateYear"];
        }
		if(isset($paramarray["monthMonth"])&&(!empty($paramarray["monthMonth"]))){
            $this->monthMonth = $paramarray["monthMonth"];
        }
		if(isset($paramarray["monthYear"])&&(!empty($paramarray["monthYear"]))){
            $this->monthYear = $paramarray["monthYear"];
        }
		if(isset($paramarray["rangeFromMonth"])&&(!empty($paramarray["rangeFromMonth"]))){
            $this->rangeFromMonth = $paramarray["rangeFromMonth"];
        }else{
        	$this->rangeFromMonth = date('n',mktime(0, 0, 0, date("m")  , date("d")-$this->rangeDays, date("Y")));
        }
		if(isset($paramarray["rangeFromDay"])&&(!empty($paramarray["rangeFromDay"]))){
            $this->rangeFromDay = $paramarray["rangeFromDay"];
        }else{
        	$this->rangeFromDay = date('j',mktime(0, 0, 0, date("m")  , date("d")-$this->rangeDays, date("Y")));
        }
		if(isset($paramarray["rangeFromYear"])&&(!empty($paramarray["rangeFromYear"]))){
            $this->rangeFromYear = $paramarray["rangeFromYear"];
        }else{
        	$this->rangeFromYear = date('Y',mktime(0, 0, 0, date("m")  , date("d")-$this->rangeDays, date("Y")));
        }
		if(isset($paramarray["rangeToMonth"])&&(!empty($paramarray["rangeToMonth"]))){
            $this->rangeToMonth = $paramarray["rangeToMonth"];
        }else{
        	$this->rangeToMonth = date('n');
        }
		if(isset($paramarray["rangeToDay"])&&(!empty($paramarray["rangeToDay"]))){
            $this->rangeToDay = $paramarray["rangeToDay"];
        }else{
        	$this->rangeToDay = date('j');
        }
		if(isset($paramarray["rangeToYear"])&&(!empty($paramarray["rangeToYear"]))){
            $this->rangeToYear = $paramarray["rangeToYear"];
        }else{
        	$this->rangeToYear = date('Y');
        }
        /*
        if(($this->dateFormat == "range") && ($this->rangeFromDay == 0)){
        	
        }
		if(($this->dateFormat == "range") && ($this->rangeFromMonth == 0)){
        	
        }
		if(($this->dateFormat == "range") && ($this->rangeFromYear == 0)){
        	
        }
		*/
        /*
        $this->cookiefile = realpath(dirname(__FILE__)."/../".$this->cookiefolder)."/".$this->cookiefile;
		$this->reportFile = realpath(dirname(__FILE__)."/../".$this->reportFolder)."/".$this->reportName.'.xml';
		*/
        
        $this->cookiefile = $this->cookiefolder."/".$this->cookiefile;
        $this->reportFolder .= "/".$this->collection;
		$this->reportFile = $this->reportFolder.'/'.$this->reportName.'.xml';
		
	}
	/**
	 * Does a request to $url with array $data as post values. Returns result or curl error
	 *
	 * @param string $url
	 * @param array $data
	 * @return string
	 */
	public function request($url = null, $data, $post = true){
		if(!is_writeable($this->cookiefile)){
			if (!touch($this->cookiefile)){
				die("Cookiefile does not exist and/or is not writable. $this->cookiefile\n");
			}
		}
		if(!isset($url)||is_null($url)||empty($url)){
			$url = $this->baseUrl;
		}
		$ch = curl_init();
		
		curl_setopt($ch,	 CURLOPT_URL, $url);
		curl_setopt($ch,     CURLOPT_RETURNTRANSFER, 1);
	    //curl_setopt($ch,     CURLOPT_VERBOSE, 1); ########### debug
	    //curl_setopt($ch,     CURLOPT_USERAGENT, $agent);
	    //curl_setopt($ch,     CURLOPT_HTTPHEADER, $header);
	    curl_setopt($ch,     CURLOPT_FOLLOWLOCATION, 1);
	    curl_setopt($ch,     CURLOPT_COOKIEJAR, $this->cookiefile);
	    curl_setopt($ch,     CURLOPT_COOKIEFILE, $this->cookiefile);
	    if($post === true){
		    curl_setopt($ch,     CURLOPT_POST, 1);
		    curl_setopt($ch,     CURLOPT_POSTFIELDS, $data);
	    }else{
	    	
	    }
	    curl_setopt($ch,	CURLOPT_TIMEOUT, 5);
		$output = curl_exec($ch);
		$info = curl_getinfo($ch);
		//var_dump($output);
		//var_dump($info);
		//print_r($data);
		if ($output === false || $info['http_code'] != 200) {
		  $output = "No cURL data returned for $url [". $info['http_code']. "]";
		    $output .= "\n". curl_error($ch);
		}
		else {
			//echo ($this->verbose ?  "Curl succeded.\n" : "");
		}
		curl_close($ch);
		
		return $output;
	}
	
	/**
	 * Alias for authenticateUser
	 *
	 * @return bool
	 */
	
	public function login(){
		
		return $this->authenticateUser();
	}
	
	/**
	 * Login 
	 *
	 * @return bool
	 */
	public function authenticateUser(){
		echo ($this->verbose ? "Logging in as $this->username \n" : "");
		
		$requestData = array(	'actionType' => 'authenticateUser', 
								'userName' => $this->username, 
								'password' => $this->password);
		$result = $this->request($this->baseUrl, $requestData);
		
		if(stripos($result, 'Log Out') === false){
			echo ($this->verbose ? "Log in failed\n$result\n" : "");
			return false;
		}else{
			echo ($this->verbose ? "Log in succeded\n" : "");
			return true;
		}
	}
	
	public function crawlStatus(){
		$requestData = array('actionType' => 'crawlStatus');
		$result = $this->request($this->baseUrl, $requestData);
		if(stripos($result, 'Log Out') === false){
			return false;
		}else{
			return $result;
		}
	}
	
	public function getSecurityToken(){
		$requestData = array();
		$result = $this->request($this->baseUrl.'?actionType=listReports', $requestData, false);
		$pos = stripos($result,'name="security_token" value="');
		$start = stripos($result,'"',$pos+29);
		$this->security_token = substr($result,$pos+29,$start-($pos+29));
	}
	
	public function generateReport($paramArray = array()){
		$this->deleteReport();
		/**We do this to change collection*/
		$this->isReportStarted();
		if($this->dateFormat == "range"){
		
		}elseif($this->dateFormat == "month"){
			
		}elseif($this->dateFormat == "recent"){
			
		}elseif($this->dateFormat == "date"){
			
		}
		$this->getSecurityToken();
		$requestData = array(
			"collection"		=> $this->collection,
			"reportType"		=> "1",
			"reportName"		=> $this->reportName,
			"withResults"		=> "true",
			"dateFormat"		=> $this->dateFormat,
			"recentDate"		=> $this->recentDate,
			"dateMonth"			=> $this->dateMonth,
			"dateDay"			=> $this->dateDay,
			"dateYear" 			=> $this->dateYear,
			"monthMonth"		=> $this->monthMonth,
			"monthYear"			=> $this->monthYear,
			"rangeFromMonth"	=> $this->rangeFromMonth,
			"rangeFromDay"		=> $this->rangeFromDay,
			"rangeFromYear"		=> $this->rangeFromYear,
			"rangeToMonth"		=> $this->rangeToMonth,
			"rangeToDay"		=> $this->rangeToDay,
			"rangeToYear"		=> $this->rangeToYear,
			"security_token"	=> $this->security_token,
			"diagnosticTerms"	=> "",
			"topCount"			=> $this->topCount,
			"actionType"		=> "generateReport",
			"generateReport" 	=> "Generate+Report"
  		);
  		
  		
  		
  		$this->request($this->baseUrl, $requestData);
  		$i = 0;
  		if(!$this->isReportStarted()){
  			echo "Report didn't start\n";
  			//print_r($requestData);
  			return false;
  		}
  		echo ($this->verbose ? "Waiting for GSA to generate report ".$this->reportName."\n" : "");
  		
  		while(!$this->isReportFinnished() && $i < $this->waitIterations){
  			echo ($this->verbose ? "." : "");
  			sleep($this->waitSeconds);
  			$i++;
  		}
  		
  		if($i < $this->waitIterations){
  			echo ($this->verbose ? "Report finnished after ".($i*$this->waitSeconds)."\n" : "");
  			$this->exportSummaryReport();
  			//$this->deleteReport();
  			return true;
  		}else{
  			echo ($this->verbose ? "Report didn't finnish after ".($this->waitIterations * $this->waitSeconds)." seconds.\n" : "");
  			//$this->deleteReport();
  			return false;
  		}
	}
	/**
	 * Retrieves the summary as xml and fills $reportXmlString
	 * @return void
	 */	
	public function exportSummaryReport($doLogin = false){
		$this->getSecurityToken();
		$requestData = array(	'actionType' => 'exportSummaryReport',
								'reportName' => $this->reportName,
								'collection' => $this->collection,
								"security_token"	=> $this->security_token);
		$this->reportXmlString = $this->request($this->baseUrl, $requestData); 
		//$this->reportXmlString = preg_replace_callback('|""[a-z].*""|',create_function('$matches','return str_ireplace(\'""\',\'"\',$matches[0]);'),$this->reportXmlString);
		$this->reportXmlString = preg_replace('|""([a-z].*)""|','"&quot;$1&quot;"', $this->reportXmlString);
		$this->reportXmlString = str_ireplace('&','&quot;',$this->reportXmlString);
	}
	
	private function escapeDoubleQuotes($matches){
		return str_ireplace('""','"\"',$matches[0]);
	}
	/**
	 * Reads xml from file.
	 * @return void
	 */
	public function getSummaryReportXML(){
		if(file_exists($this->reportFile)){
		 	$this->reportXmlString = trim(file_get_contents($this->reportFile));
		}elseif (file_exists(realpath(dirname(__FILE__)."/../xml/".$this->reportName.".xml"))){
			$this->reportXmlString = trim(file_get_contents(realpath(dirname(__FILE__)."/../xml/".$this->reportName.".xml")));
		}else{
			echo "No file".$this->reportFile;
		}
	}
	/**
	 * Checks if a report with $reportName is generating or has been generated. Looks for the name on the page with list of reports
	 *
	 * @return bool
	 */
	public function isReportStarted(){
		$requestData = array(	'actionType' => 'listReports',
								'selectedCollection' => $this->collection);
		$result = $this->request($this->baseUrl.'?actionType=listReports', $requestData, false);
		if(stripos($result, $this->reportName) === false){
			echo ($this->verbose ? "The report didn't start\n" : "");
			return false;
		}
		echo ($this->verbose ? "Report started.\n" : "");
		return true;
	}
	/**
	 * Checks that a report has finnished. It is finnished if the name occurs on the page with list of reports, and the word Generating is not present.
	 *
	 * @return bool
	 */
	public function isReportFinnished(){
		$requestData = array(	'actionType' => 'listReports',
								'selectedCollection' => $this->collection);
		$result = $this->request($this->baseUrl.'?actionType=listReports', $requestData,false);
		if((stripos($result, 'List of search reports') !== false) && (stripos($result, 'Generating') === false) && (stripos($result, $this->reportName) !== false)){
			echo ($this->verbose ? "Report is finnished.\n" : "");
			return true;
		}else{
			
			return false;
		}
	}
	/**
	 * Deletes report from GSA-box
	 * @return void
	 */
	public function deleteReport(){
		$requestData = array(	'actionType' => 'deleteReport', 
								'reportType' => '1', 
								'reportName' => $this->reportName, 
								'collection' => $this->collection);
		$this->getSecurityToken();
		$result = $this->request($this->baseUrl.'?actionType=deleteReport&reportType=1&reportName='.$this->reportName.'&collection='.$this->collection, $requestData, false);
	}
	/**
	 * Logout
	 * 
	 * @return void
	 *
	 */
	public function logOut(){
		$requestData = array(	'actionType' => 'logout');
		$this->request($this->baseUrl, $requestData);
	}
	
	/**
	 * @desc saves the report in a file
	 * @return void
	 */
	public function saveReport(){
		if(stripos($this->reportXmlString,'<summaryReport>') === 0){
			if(!is_dir($this->reportFolder)){
				if(!mkdir($this->reportFolder,0777)){
					echo "Couldn't create folder ".$this->reportFolder;
					return false;
				}
			}
			$fp = fopen($this->reportFile, 'w');
			if($fp !== false){
				fwrite($fp, $this->reportXmlString);
				fclose($fp);
				echo ($this->verbose ? "Report was saved.\n".$this->reportFile."\n" : "");
				return true;
			}else{
				echo "Couldn't open file ".$this->reportFile."\n";
				return false;
			}
		}
		echo "Report seems incomplete. \n".$this->reportXmlString."\n";
		return false;
	}
	
	/**
	 * Switch between collections
	 */
	public function switchCollections($collection){
		$requestData = array(	'actionType' => 'listReports', 
								'selectedCollection' => $collection);
		$this->getSecurityToken();
		$this->request($this->baseUrl, $requestData);
	}
}
